﻿using SqlSugar;
using SwaggerJwtAuthenticationCenter.Helper;
using SwaggerJwtAuthenticationCenter.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace SwaggerJwtAuthenticationCenter.DbHelper.Base
{
    public abstract class SimpelRepository : IBaseRepository
    {
        private bool IsMutiDb = false;
        protected SqlSugarClient _sqlSugarClient = null;

        protected SimpelRepository(List<MultiDBConfig> dBConfigs)
        {
            List<ConnectionConfig> connectionConfigs = dBConfigs.Select(e => e.ConvertToConnConfig()).ToList();
            if (dBConfigs != null && dBConfigs.Count > 1) IsMutiDb = true;
            _sqlSugarClient = new SqlSugarClient(connectionConfigs);
        }



        protected SqlSugarClient GetDbClient<T>()
        {
            if (IsMutiDb)
            {
                if (typeof(T).GetTypeInfo().GetCustomAttributes(typeof(SugarTable), true).FirstOrDefault((x => x.GetType() == typeof(SugarTable))) is SugarTable sugarTable && !string.IsNullOrEmpty(sugarTable.TableDescription))
                {
                    _sqlSugarClient.ChangeDatabase(sugarTable.TableDescription.ToLower());
                }
            }
            return _sqlSugarClient;
        }

        public IAdo Ado<T>()
        {
            return GetDbClient<T>().Ado;
        }

        #region 操作


        #region 查询
        /// <summary>
        /// 功能描述:查询数据列表
        /// 作　　者:yyf
        /// </summary>
        /// <param name="whereExpression">whereExpression</param>
        /// <returns>数据列表</returns>
        public async Task<List<T>> Query<T>(Expression<Func<T, bool>> whereExpression) where T : class, new()
        {
            return await GetDbClient<T>().Queryable<T>().WhereIF(whereExpression != null, whereExpression).ToListAsync();
        }
        /// <summary>
        /// 功能描述:查询数据列表
        /// 作　　者:yyf
        /// </summary>
        /// <param name="whereExpression">whereExpression</param>
        /// <returns>数据列表</returns>
        public async Task<List<T>> QueryOrderBy<T>(Expression<Func<T, bool>> whereExpression, Expression<Func<T, object>> orderExpression = null, OrderByType orderType = OrderByType.Desc) where T : class, new()
        {
            return await GetDbClient<T>().Queryable<T>().WhereIF(whereExpression != null, whereExpression).OrderByIF(orderExpression != null, orderExpression, orderType).ToListAsync();
        }
        /// <summary>
        /// 功能描述:查询数据列表
        /// 作　　者:yyf
        /// </summary>
        /// <param name="strWhere">条件</param>
        /// <returns>数据列表</returns>
        public async Task<List<T>> Query<T>(string strWhere) where T : class, new()
        {
            //return await Task.Run(() => GetDbClient ().Queryable<T>().WhereIF(!string.IsNullOrEmpty(strWhere), strWhere).ToList());
            return await GetDbClient<T>().Queryable<T>().WhereIF(!string.IsNullOrEmpty(strWhere), strWhere).ToListAsync();
        }

        /// <summary>
        /// 查询单个实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<T> QuerySingle<T>(Expression<Func<T, bool>> expression) where T : class, new()
        {
            var querys = await GetDbClient<T>().Queryable<T>().WhereIF(expression != null, expression).ToListAsync();
            if (querys.Count > 0) return querys.First();
            else return null;
        }
        /// <summary>
        /// 功能描述:查询所有数据
        /// 作　　者:yyf
        /// </summary>
        /// <returns>数据列表</returns>
        public async Task<List<T>> Query<T>() where T : class, new()
        {
            return await GetDbClient<T>().Queryable<T>().ToListAsync();
        }
        public async Task<List<T>> QueryListBySql<T>(string sql) where T : class, new()
        {
            var models = await GetDbClient<T>().SqlQueryable<T>(sql).ToListAsync();
            return models;
        }
        public async Task<T> QuerySingleBySql<T>(string sql) where T : class, new()
        {
            var models = await GetDbClient<T>().SqlQueryable<T>(sql).ToListAsync();
            return models.Count > 0 ? models.First() : null;
        }

        /// <summary>
        /// 功能描述:查询一个列表
        /// 作　　者:yyf
        /// </summary>
        /// <param name="whereExpression">条件表达式</param>
        /// <param name="strOrderByFileds">排序字段，如name asc,age desc</param>
        /// <returns>数据列表</returns>
        public async Task<List<T>> Query<T>(Expression<Func<T, bool>> whereExpression, string strOrderByFileds) where T : class, new()
        {
            //return await Task.Run(() => GetDbClient ().Queryable<T>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(whereExpression != null, whereExpression).ToList());
            return await GetDbClient<T>().Queryable<T>().WhereIF(whereExpression != null, whereExpression).OrderByIF(strOrderByFileds != null, strOrderByFileds).ToListAsync();
        }

        /// <summary>
        /// 功能描述:查询一个列表
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="orderByExpression"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public async Task<List<T>> Query<T>(Expression<Func<T, bool>> whereExpression, Expression<Func<T, object>> orderByExpression, bool isAsc = true) where T : class, new()
        {
            //return await Task.Run(() => GetDbClient ().Queryable<T>().OrderByIF(orderByExpression != null, orderByExpression, isAsc ? OrderByType.Asc : OrderByType.Desc).WhereIF(whereExpression != null, whereExpression).ToList());
            return await GetDbClient<T>().Queryable<T>().OrderByIF(orderByExpression != null, orderByExpression, isAsc ? OrderByType.Asc : OrderByType.Desc).WhereIF(whereExpression != null, whereExpression).ToListAsync();
        }

        /// <summary>
        /// 功能描述:查询一个列表
        /// 作　　者:yyf
        /// </summary>
        /// <param name="strWhere">条件</param>
        /// <param name="strOrderByFileds">排序字段，如name asc,age desc</param>
        /// <returns>数据列表</returns>
        public async Task<List<T>> Query<T>(string strWhere, string strOrderByFileds) where T : class, new()
        {
            return await GetDbClient<T>().Queryable<T>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(!string.IsNullOrEmpty(strWhere), strWhere).ToListAsync();
        }

        /// <summary>
        /// 功能描述:查询前N条数据
        /// 作　　者:yyf
        /// </summary>
        /// <param name="whereExpression">条件表达式</param>
        /// <param name="intTop">前N条</param>
        /// <param name="strOrderByFileds">排序字段，如name asc,age desc</param>
        /// <returns>数据列表</returns>
        public async Task<List<T>> Query<T>(Expression<Func<T, bool>> whereExpression, int intTop, string strOrderByFileds) where T : class, new()
        {
            return await GetDbClient<T>().Queryable<T>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(whereExpression != null, whereExpression).Take(intTop).ToListAsync();
        }

        /// <summary>
        /// 功能描述:查询前N条数据
        /// 作　　者:yyf
        /// </summary>
        /// <param name="strWhere">条件</param>
        /// <param name="intTop">前N条</param>
        /// <param name="strOrderByFileds">排序字段，如name asc,age desc</param>
        /// <returns>数据列表</returns>
        public async Task<List<T>> Query<T>(string strWhere, int intTop, string strOrderByFileds) where T : class, new()
        {
            return await GetDbClient<T>().Queryable<T>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(!string.IsNullOrEmpty(strWhere), strWhere).Take(intTop).ToListAsync();
        }

        /// <summary>
        /// 功能描述:分页查询
        /// 作　　者:yyf
        /// </summary>
        /// <param name="whereExpression">条件表达式</param>
        /// <param name="intPageIndex">页码（下标0）</param>
        /// <param name="intPageSize">页大小</param>
        /// <param name="intTotalCount">数据总量</param>
        /// <param name="strOrderByFileds">排序字段，如name asc,age desc</param>
        /// <returns>数据列表</returns>
        public async Task<List<T>> Query<T>(Expression<Func<T, bool>> whereExpression, int intPageIndex, int intPageSize, string strOrderByFileds) where T : class, new()
        {
            return await GetDbClient<T>().Queryable<T>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(whereExpression != null, whereExpression).ToPageListAsync(intPageIndex, intPageSize);
        }

        /// <summary>
        /// 功能描述:分页查询
        /// 作　　者:yyf
        /// </summary>
        /// <param name="strWhere">条件</param>
        /// <param name="intPageIndex">页码（下标0）</param>
        /// <param name="intPageSize">页大小</param>
        /// <param name="intTotalCount">数据总量</param>
        /// <param name="strOrderByFileds">排序字段，如name asc,age desc</param>
        /// <returns>数据列表</returns>
        public async Task<List<T>> Query<T>(string strWhere, int intPageIndex, int intPageSize, string strOrderByFileds) where T : class, new()
        {
            return await GetDbClient<T>().Queryable<T>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(!string.IsNullOrEmpty(strWhere), strWhere).ToPageListAsync(intPageIndex, intPageSize);
        }

        /// <summary>
        /// 分页查询[使用版本，其他分页未测试]
        /// </summary>
        /// <param name="whereExpression">条件表达式</param>
        /// <param name="intPageIndex">页码（下标0）</param>
        /// <param name="intPageSize">页大小</param>
        /// <param name="strOrderByFileds">排序字段，如name asc,age desc</param>
        /// <returns></returns>
        public async Task<PageModel<T>> QueryPage<T>(Expression<Func<T, bool>> whereExpression, int intPageIndex = 1, int intPageSize = 20, string strOrderByFileds = null) where T : class, new()
        {

            RefAsync<int> totalCount = 0;
            var list = await GetDbClient<T>().Queryable<T>()
             .OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds)
             .WhereIF(whereExpression != null, whereExpression)
             .ToPageListAsync(intPageIndex, intPageSize, totalCount);
            int pageCount = (Math.Ceiling(totalCount.ObjToDecimal() / intPageSize.ObjToDecimal())).ObjToInt();
            return new PageModel<T>() { dataCount = totalCount, pageCount = pageCount, page = intPageIndex, PageSize = intPageSize, data = list };
        }

        public async Task<T> QueryById<T>(object objId) where T : class, new()
        {
            return await GetDbClient<T>().Queryable<T>().In(objId).SingleAsync();
        }

        /// <summary>
        /// 功能描述:根据ID查询一条数据
        /// 作　　者:yyf
        /// </summary>
        /// <param name="objId">id（必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]），如果是联合主键，请使用Where条件</param>
        /// <param name="blnUseCache">是否使用缓存</param>
        /// <returns>数据实体</returns>
        public async Task<T> QueryById<T>(object objId, bool blnUseCache = false) where T : class, new()
        {
            //return await Task.Run(() => GetDbClient ().Queryable<T>().WithCacheIF(blnUseCache).InSingle(objId));
            return await GetDbClient<T>().Queryable<T>().WithCacheIF(blnUseCache).In(objId).SingleAsync();
        }

        /// <summary>
        /// 功能描述:根据ID查询数据
        /// 作　　者:yyf
        /// </summary>
        /// <param name="lstIds">id列表（必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]），如果是联合主键，请使用Where条件</param>
        /// <returns>数据实体列表</returns>
        public async Task<List<T>> QueryByIDs<T>(object[] lstIds) where T : class, new()
        {
            //return await Task.Run(() => GetDbClient ().Queryable<T>().In(lstIds).ToList());
            return await GetDbClient<T>().Queryable<T>().In(lstIds).ToListAsync();
        }

        /// <summary> 
        ///查询-多表查询
        /// </summary> 
        /// <typeparam name="T">实体1</typeparam> 
        /// <typeparam name="T2">实体2</typeparam> 
        /// <typeparam name="T3">实体3</typeparam>
        /// <typeparam name="TResult">返回对象</typeparam>
        /// <param name="joinExpression">关联表达式 (join1,join2) => new object[] {JoinType.Left,join1.UserNo==join2.UserNo}</param> 
        /// <param name="selectExpression">返回表达式 (s1, s2) => new { Id =s1.UserNo, Id1 = s2.UserNo}</param>
        /// <param name="whereLambda">查询表达式 (w1, w2) =>w1.UserNo == "")</param> 
        /// <returns>值</returns>
        public async Task<List<TResult>> QueryMuch<T, T2, T3, TResult>(Expression<Func<T, T2, T3, object[]>> joinExpression, Expression<Func<T, T2, T3, TResult>> selectExpression, Expression<Func<T, T2, T3, bool>> whereLambda = null) where T : class, new()
        {
            if (whereLambda == null)
            {
                return await GetDbClient<T>().Queryable(joinExpression).Select(selectExpression).ToListAsync();
            }
            return await GetDbClient<T>().Queryable(joinExpression).Where(whereLambda).Select(selectExpression).ToListAsync();
        }

        public async Task<List<TResult>> QueryMuch<T, T2, TResult>(
            Expression<Func<T, T2, object[]>> joinExpression,
            Expression<Func<T, T2, TResult>> selectExpression,
            Expression<Func<T, T2, bool>> whereLambda = null) where T : class, new()
        {
            if (whereLambda == null)
            {
                return await GetDbClient<T>().Queryable(joinExpression).Select(selectExpression).ToListAsync();
            }
            return await GetDbClient<T>().Queryable(joinExpression).Where(whereLambda).Select(selectExpression).ToListAsync();
        }

        public async Task<List<TResult>> QueryMuch<T, T2, TResult>(Expression<Func<T, T2, object[]>> joinExpression, Expression<Func<T, T2, TResult>> selectExpression, string whereStr = null) where T : class, new()
        {
            if (string.IsNullOrWhiteSpace(whereStr))
            {
                return await GetDbClient<T>().Queryable(joinExpression).Select(selectExpression).ToListAsync();
            }
            return await GetDbClient<T>().Queryable(joinExpression).Where(whereStr).Select(selectExpression).ToListAsync();
        }

        public async Task<bool> ExecuteSql<T>(string sql, List<SugarParameter> parameters = null) where T : class, new()
        {
            if (parameters == null)
            {
                var result1 = await GetDbClient<T>().Ado.ExecuteCommandAsync(sql, new List<SugarParameter>());
                return result1 > 0;
            }
            var result = await GetDbClient<T>().Ado.ExecuteCommandAsync(sql, parameters);
            return result > 0;
        }
        #endregion

        #region 新增


        /// <summary>
        /// 写入实体数据
        /// </summary>
        /// <param name="entity">博文实体类</param>
        /// <returns></returns>
        public async Task<int> Add<T>(T entity) where T : class, new()
        {
            var insert = GetDbClient<T>().Insertable(entity);
            return await insert.ExecuteReturnIdentityAsync();
        }

        /// <summary>
        /// 写入实体数据
        /// </summary>
        /// <param name="entity">实体类</param>
        /// <param name="insertColumns">指定只插入列</param>
        /// <returns>返回自增量列</returns>
        public async Task<int> Add<T>(T entity, Expression<Func<T, object>> insertColumns = null) where T : class, new()
        {
            var insert = GetDbClient<T>().Insertable(entity);
            if (insertColumns == null)
            {
                return await insert.ExecuteReturnIdentityAsync();
            }
            else
            {
                return await insert.InsertColumns(insertColumns).ExecuteReturnIdentityAsync();
            }
        }

        /// <summary>
        /// 批量插入实体(速度快)
        /// </summary>
        /// <param name="lisT">实体集合</param>
        /// <returns>影响行数</returns>
        public async Task<int> Add<T>(List<T> lisT) where T : class, new()
        {
            return await GetDbClient<T>().Insertable(lisT.ToArray()).ExecuteCommandAsync();
        }

        #endregion

        #region 删除
        /// <summary>
        /// 根据实体删除一条数据
        /// </summary>
        /// <param name="entity">博文实体类</param>
        /// <returns></returns>
        public async Task<bool> Delete<T>(T entity) where T : class, new()
        {
            //var i = await Task.Run(() => GetDbClient ().Deleteable(entity).ExecuteCommand());
            //return i > 0;
            return await GetDbClient<T>().Deleteable(entity).ExecuteCommandHasChangeAsync();
        }

        /// <summary>
        /// 删除指定ID的数据
        /// </summary>
        /// <param name="id">主键ID</param>
        /// <returns></returns>
        public async Task<bool> DeleteById<T>(object id) where T : class, new()
        {
            return await GetDbClient<T>().Deleteable<T>(id).ExecuteCommandHasChangeAsync();
        }

        /// <summary>
        /// 删除指定ID集合的数据(批量删除)
        /// </summary>
        /// <param name="ids">主键ID集合</param>
        /// <returns></returns>
        public async Task<bool> DeleteByIds<T>(object[] ids) where T : class, new()
        {
            return await GetDbClient<T>().Deleteable<T>().In(ids).ExecuteCommandHasChangeAsync();
        }


        #endregion

        #region 更新
        /// <summary>
        /// 更新实体数据
        /// </summary>
        /// <param name="entity">博文实体类</param>
        /// <returns></returns>
        public async Task<bool> Update<T>(T entity) where T : class, new()
        {
            return await GetDbClient<T>().Updateable<T>(entity).ExecuteCommandHasChangeAsync();
        }

        /// <summary>
        /// 更新实体数据
        /// </summary>
        /// <param name="entity">实体类</param>
        /// <param name="strWhere">条件</param>
        /// <returns></returns>
        public async Task<bool> Update<T>(T entity, string strWhere) where T : class, new()
        {
            return await GetDbClient<T>().Updateable(entity).Where(strWhere).ExecuteCommandHasChangeAsync();
        }

        /// <summary>
        /// 更新实体类
        /// </summary>
        /// <param name="strSql">sql语句</param>
        /// <param name="parameters">sugerParameter</param>
        /// <returns></returns>
        public async Task<bool> Update<T>(string strSql, SugarParameter[] parameters = null) where T : class, new()
        {
            return await GetDbClient<T>().Ado.ExecuteCommandAsync(strSql, parameters) > 0;
        }

        /// <summary>
        /// 更新实体类，动态对象
        /// </summary>
        /// <param name="operateAnonymousObjects">动态对象</param>
        /// <returns></returns>
        public async Task<bool> Update<T>(object operateAnonymousObjects) where T : class, new()
        {
            return await GetDbClient<T>().Updateable<T>(operateAnonymousObjects).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 更新实体类
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <param name="lstColumns">指定要更新的列</param>
        /// <param name="lstIgnoreColumns">指定不用更新的类</param>
        /// <param name="strWhere">where条件</param>
        /// <returns></returns>
        public async Task<bool> Update<T>(T entity, List<string> lstColumns = null, List<string> lstIgnoreColumns = null, string strWhere = "") where T : class, new()
        {
            {
                IUpdateable<T> up = GetDbClient<T>().Updateable(entity);
                if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0)
                {
                    up = up.IgnoreColumns(lstIgnoreColumns.ToArray());
                }
                if (lstColumns != null && lstColumns.Count > 0)
                {
                    up = up.UpdateColumns(lstColumns.ToArray());
                }
                if (!string.IsNullOrEmpty(strWhere))
                {
                    up = up.Where(strWhere);
                }
                return await up.ExecuteCommandHasChangeAsync();
            }
        }

        #endregion
        #endregion

        #region 事务
        public void BeginTran<T>() where T : class, new()
        {
            GetDbClient<T>().BeginTran();
        }

        public void CommitTran<T>() where T : class, new()
        {
            try
            {
                GetDbClient<T>().CommitTran(); //
            }
            catch (Exception ex)
            {
                GetDbClient<T>().RollbackTran();
                throw ex;
            }
        }

        public void RollbackTran<T>() where T : class, new()
        {
            GetDbClient<T>().RollbackTran();
        }

        #endregion
    }
}
